package com.avcompris.util;

import static com.avcompris.util.ExceptionUtils.nonNullArgument;
import static org.apache.commons.io.FileUtils.openInputStream;
import static org.apache.commons.lang3.CharEncoding.UTF_8;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

import org.jvyaml.YAML;
import org.yaml.snakeyaml.Yaml;

import com.avcompris.common.annotation.Nullable;

/**
 * utility class for YAML manipulation via the SnakeYAML API.
 * 
 * @author David Andriana Copyright Avantage Compris SARL 2009 ©
 */
public abstract class SnakeYAMLUtils extends AbstractUtils {

	/**
	 * load a YAML file into a {@link YAML} object.
	 * 
	 * @param yamlFile
	 *            the YAML input file
	 * @return the loaded {@link YAML} object.
	 */
	@Nullable
	public static Object loadYAML(final File yamlFile) throws IOException {

		nonNullArgument(yamlFile, "yamlFile");

		final Object yaml;

		final InputStream is = openInputStream(yamlFile);
		try {

			final Reader reader = new InputStreamReader(is, UTF_8);

			yaml = new Yaml().load(reader);

		} finally {
			is.close();
		}

		return yaml;
	}

	/**
	 * load all YAML documents from a YAML file into an array of {@link YAML}
	 * objects.
	 * 
	 * @param yamlFile
	 *            the YAML input file
	 * @return the loaded {@link YAML} objects.
	 */
	@Nullable
	public static Object[] loadAllYAML(final File yamlFile) throws IOException {

		nonNullArgument(yamlFile, "yamlFile");

		final Iterable<Object> yamls;

		final InputStream is = openInputStream(yamlFile);
		try {

			final Reader reader = new InputStreamReader(is, UTF_8);

			yamls = new Yaml().loadAll(reader);

		} finally {
			is.close();
		}

		final List<Object> objects = new ArrayList<Object>();

		for (final Object yaml : yamls) {

			objects.add(yaml);
		}

		return objects.toArray();
	}

	/**
	 * load a YAML file into a {@link YAML} object.
	 * 
	 * @param yamlReader
	 *            the YAML input stream
	 * @return the loaded {@link YAML} object.
	 */
	@Nullable
	public static Object loadYAML(final Reader yamlReader) {

		nonNullArgument(yamlReader, "yamlReader");

		return new Yaml().load(yamlReader);
	}

	/**
	 * load a YAML resource into a {@link YAML} object.
	 * 
	 * @param classLoader
	 *            the {@link ClassLoader} to use to read the resource
	 * @param yamlResource
	 *            the YAML resource file to read
	 * @return the loaded {@link YAML} object.
	 */
	public static Object loadYAMLResource(final ClassLoader classLoader,
			final String yamlResource) throws IOException {

		nonNullArgument(classLoader, "classLoader");
		nonNullArgument(yamlResource, "yamlResource");

		final Object yaml;

		final InputStream is = classLoader.getResourceAsStream(yamlResource);

		if (is == null) {
			throw new NullPointerException("Cannot find YAML resource: "
					+ yamlResource);
		}
		try {

			final Reader reader = new InputStreamReader(is, UTF_8);

			yaml = new Yaml().load(reader);

		} finally {
			is.close();
		}

		return yaml;
	}

	/**
	 * load a YAML resource into a {@link YAML} object.
	 * 
	 * @param c
	 *            the {@link Class} from which to read the resource
	 * @param yamlResource
	 *            the YAML resource file to read
	 * @return the loaded {@link YAML} object.
	 */
	public static Object loadYAMLResource(final Class<?> c,
			final String yamlResource) throws IOException {

		nonNullArgument(c, "class");

		return loadYAMLResource(c.getClassLoader(), yamlResource);
	}

	/**
	 * load a YAML {@link String} into a {@link YAML} object.
	 * 
	 * @param text
	 *            the YAML input content
	 * @return the loaded {@link YAML} object.
	 */
	@Nullable
	public static Object loadYAML(final String text) {

		nonNullArgument(text, "text");

		final Object yaml;

		final Reader reader = new StringReader(text);

		yaml = new Yaml().load(reader);

		return yaml;
	}
}
